﻿using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.ComponentModel;
using System.Linq;
using System.Text;
using System.Web.DynamicData;
using System.Web.UI;
using System.Web.UI.HtmlControls;
using System.Web.UI.WebControls;
using NotAClue;
//using NotAClue.ComponentModel.DataAnnotations;
using NotAClue.Web;
using System.Collections;

namespace NotAClue.Web
{
    public static class ControlExtensionMethods
    {
        /// <summary>
        /// Gets the node.
        /// </summary>
        /// <param name="menu">The menu.</param>
        /// <param name="title">The title.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static MenuItem GetNode(this Menu menu, String title)
        {
            foreach (MenuItem item in menu.Items)
            {
                if (item.Text == title)
                    return item;
            }
            return null;
        }

        /// <summary>
        /// Adds the after node.
        /// </summary>
        /// <param name="menu">The menu.</param>
        /// <param name="title">The title.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static MenuItem GetNodeAfter(this Menu menu, String title)
        {
            for (int i = 0; i < menu.Items.Count; i++)
            {
                if (menu.Items[i].Text == title && i > 0)
                    return menu.Items[i + 1];
            }
            return null;
        }

        /// <summary>
        /// Adds the before node.
        /// </summary>
        /// <param name="menu">The menu.</param>
        /// <param name="title">The title.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static MenuItem GetNodeBefore(this Menu menu, String title)
        {
            for (int i = 0; i < menu.Items.Count; i++)
            {
                if (menu.Items[i].Text == title && i > 0)
                    return menu.Items[i - 1];
            }
            return null;
        }

        /// <summary>
        /// Replaces the node.
        /// </summary>
        /// <param name="menu">The menu.</param>
        /// <param name="menuItem">The menu item.</param>
        /// <remarks></remarks>
        public static void ReplaceNode(this Menu menu, MenuItem menuItem)
        {
            for (int i = 0; i < menu.Items.Count; i++)
            {
                if (menu.Items[i].Text == menuItem.Text && i > 0)
                {
                    menu.Items.RemoveAt(i);
                    menu.Items.AddAt(i, menuItem);
                }
            }
        }

        /// <summary>
        /// Adds after the control.
        /// </summary>
        /// <param name="control">The control.</param>
        /// <param name="controlToAdd">The control1.</param>
        /// <remarks></remarks>
        public static void AddAfter(this Control control, Control controlToAdd)
        {
            var parent = control.Parent;
            var index = parent.Controls.IndexOf(control);
            parent.Controls.AddAt(index + 1, controlToAdd);
        }

        /// <summary>
        /// Fills the enum list control.
        /// </summary>
        /// <param name="list">The list.</param>
        /// <param name="enumType">Type of the enum.</param>
        public static void FillEnumListControl(this ListControl list, Type enumType)
        {
            foreach (DictionaryEntry entry in EnumExtensionMethods.GetEnumNamesAndValues(enumType))
            {
                list.Items.Add(new ListItem((string)entry.Key, ((string)entry.Value).ToTitleFromPascal()));
            }
        }

        /// <summary>
        /// Gets the enum list.
        /// </summary>
        /// <param name="enumType">Type of the enum.</param>
        /// <returns></returns>
        public static List<ListItem> GetEnumList(Type enumType)
        {
            var list = new List<ListItem>();
            foreach (DictionaryEntry entry in EnumExtensionMethods.GetEnumNamesAndValues(enumType))
            {
                list.Add(new ListItem((string)entry.Key, (string)entry.Value));
            }
            return list;
        }

        /// <summary>
        /// Determines whether the specified list control has selection.
        /// </summary>
        /// <param name="listControl">The list control.</param>
        /// <param name="nullValueString">The null value string.</param>
        /// <returns><c>true</c> if the specified list control has selection; otherwise, <c>false</c>.</returns>
        /// <remarks></remarks>
        public static Boolean HasSelection(this ListControl listControl, String nullValueString = "[null]")
        {
            var selectedValue = listControl.SelectedValue;
            return (!String.IsNullOrEmpty(selectedValue) && selectedValue != nullValueString);
        }

        /// <summary>
        /// Makes sure focus is still on this control after update.
        /// </summary>
        /// <param name="webControl">The web control.</param>
        public static void SetFocusHere(this WebControl webControl)
        {
            // get reference to the pages script manager
            var scriptManagerRef = ScriptManager.GetCurrent(webControl.Page);

            // set focus to the passed in web control
            if (scriptManagerRef.EnablePartialRendering)
                scriptManagerRef.SetFocus(webControl);
            else
                webControl.Page.SetFocus(webControl);
        }

        /// <summary>
        /// Get the control by searching recursively for it.
        /// </summary>
        /// <param name="Root">The control to start the search at.</param>
        /// <param name="Id">The ID of the control to find</param>
        /// <returns>The control the was found or NULL if not found</returns>
        public static Control FindControlRecursive(this Control Root, string Id)
        {
            if (Root.ID == Id)
                return Root;

            foreach (Control Ctl in Root.Controls)
            {
                Control FoundCtl = FindControlRecursive(Ctl, Id);

                if (FoundCtl != null)
                    return FoundCtl;
            }
            return null;
        }

        /// <summary>
        /// Finds the control recursive.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="root">The root.</param>
        /// <returns></returns>
        public static T FindControlRecursive<T>(this Control root) where T : Control
        {
            var control = root as T;
            if (control != null)
                return control;

            foreach (Control Ctl in root.Controls)
            {
                T FoundCtl = Ctl.FindControlRecursive<T>();

                if (FoundCtl != null)
                    return FoundCtl;
            }
            return null;
        }

        /// <summary>
        /// Finds the control recursive.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="root">The root.</param>
        /// <param name="Id">The id.</param>
        /// <returns></returns>
        public static T FindControlRecursive<T>(this Control root, string Id) where T : Control
        {
            var control = root as T;
            if (control != null && root.ID == Id)
                return control;

            foreach (Control Ctl in root.Controls)
            {
                T FoundCtl = Ctl.FindControlRecursive<T>(Id);

                if (FoundCtl != null)
                    return FoundCtl;
            }
            return null;
        }

        /// <summary>
        /// Get the Data Control containing the FiledTemplate
        /// usually a DetailsView or FormView
        /// </summary>
        /// <param name="control">
        /// Use the current field template as a starting point
        /// </param>
        /// <returns>
        /// A FilterRepeater the control that 
        /// contains the current control
        /// </returns>
        public static T GetContainerControl<T>(this Control control) where T : Control
        {
            var parentControl = control.Parent;
            while (parentControl != null)
            {
                var p = parentControl as T;
                if (p != null)
                    return p;
                else
                    parentControl = parentControl.Parent;
            }
            return null;
        }

        /// <summary>
        /// Gets the parent control of type T.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="control">The control.</param>
        /// <returns></returns>
        public static T GetParent<T>(this Control control) where T : Control
        {
            var parentControl = control.Parent;
            while (parentControl != null)
            {
                var currentParentControl = parentControl as T;
                if (currentParentControl != null)
                    return currentParentControl;
                else
                    parentControl = parentControl.Parent;
            }
            return null;
        }

        /// <summary>
        /// Flattens hierarchy of child controls.
        /// </summary>
        /// <param name="control">The control.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static IEnumerable<Control> FlattenChildren(this Control control)
        {
            var children = control.Controls.Cast<Control>();
            return children.SelectMany(c => FlattenChildren(c)).Concat(children);
        }

        /// <summary>
        /// Gets all child controls recursive.
        /// </summary>
        /// <typeparam name="T"></typeparam>
        /// <param name="control">The control.</param>
        /// <returns></returns>
        /// <remarks></remarks>
        public static IEnumerable<T> GetAllChildControlsRecursive<T>(this Control control)
        {
            return control.FlattenChildren().OfType<T>();
        }
    }
}
